﻿using System.Collections.Generic;
using System.IO;
using System.Web.Mvc;
using HashFoo.Rest.Common;
using System.Linq;

namespace HashFoo.Rest.Server
{
    /// <summary>
    /// Deserializes resources, serialized in a request body, and "binds" them to the handlers resource object.
    /// If no deserializer exists, or there is no body, falls back on the MVC default binder.
    /// </summary>
    public class ResourceModelBinder : DefaultModelBinder
    {
        readonly IResourceSerializer[] _serializers;

        /// <summary>
        /// Creates the model binder using a set of serializers.
        /// </summary>
        /// <param name="serializers"></param>
        public ResourceModelBinder(IEnumerable<IResourceSerializer> serializers)
        {
            _serializers = serializers.ToArray();
        }

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var contentType = controllerContext.HttpContext.Request.ContentType.ToLowerInvariant();
            var serializer = _serializers.FirstOrDefault(
                s =>
                s.AcceptMimeTypes.Any(mimeType => mimeType.ToLowerInvariant() == contentType));

            if (serializer == null) return base.BindModel(controllerContext, bindingContext);

            // the stream has probably already been read by other MVC components.  grr.
            var dataStream = controllerContext.HttpContext.Request.InputStream;
            dataStream.Seek(0, SeekOrigin.Begin);

            string data;
            using (var reader = new StreamReader(dataStream))
            {
                data = reader.ReadToEnd();
            }

            return serializer.Read(data, bindingContext.ModelType);
        }
    }
}